﻿//文件指定编译编码UTF-8
#pragma execution_character_set("utf-8")
#include "disposethread.h"
#include "scanruleservice.h"

#include <qglobalconfig.h>
#include <QDebug>
#include <QDir>
#include <QDirIterator>
#include <Windows.h>

DisposeThread::DisposeThread(QObject *parent) : QThread(parent)
{
    moveToThread(this);
    isRun = false;
}

DisposeThread::~DisposeThread()
{
    stop();
    quit();
    wait();
}

void DisposeThread::stop()
{
    isRun = false;
}

bool moveFile(const QString &filePath, const QString &targetDir)
{
    if (targetDir.isEmpty()) {
        qDebug() << "目标目录为空，跳过移动：" << filePath;
        return false;
    }

    QDir dir(targetDir);
    if (!dir.exists()) {
        if (!dir.mkpath(targetDir)) {
            qDebug() << "无法创建目标目录：" << targetDir;
            return false;
        }
    }

    QFileInfo srcInfo(filePath);
    QString destPath = targetDir + "/" + srcInfo.fileName();

    // 如果文件已存在，可以选择重命名避免覆盖
    if (QFile::exists(destPath)) {
        QString baseName = srcInfo.baseName();
        QString suffix = srcInfo.suffix();
        int count = 1;
        do {
            destPath = QString("%1/%2_%3.%4").arg(targetDir).arg(baseName).arg(count++).arg(suffix);
        } while (QFile::exists(destPath));
    }

    if (QFile::rename(filePath, destPath)) {
        qDebug() << "文件已移动至：" << destPath;
        return true;
    } else {
        qWarning() << "文件移动失败：" << filePath << " -> " << destPath;
        return false;
    }
}

bool isFileOpenable(const QString &filePath)
{
    QFile file(filePath);

#if defined(Q_OS_WIN)
    // Windows 下使用 Win32 API 打开文件并设置共享模式为 0（不允许其他进程访问）
    QString nativePath = QDir::toNativeSeparators(filePath);
    HANDLE hFile = CreateFile(
                (LPCWSTR)nativePath.utf16(),
                GENERIC_READ,
                0,                      // 不允许其他进程访问（独占）
                NULL,
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                NULL
                );

    if (hFile == INVALID_HANDLE_VALUE) {
        qDebug() << "文件被占用，无法独占打开：" << filePath;
        return false;
    }

    CloseHandle(hFile); // 关闭句柄，不影响后续用 QFile 打开
    return true;

#elif defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
    // Linux/macOS 使用 flock 尝试加锁
    int fd = open(filePath.toLocal8Bit().data(), O_RDONLY);
    if (fd == -1) {
        qDebug() << "无法打开文件：" << filePath;
        return false;
    }

    struct flock fl;
    fl.l_type = F_RDLCK;     // 读锁
    fl.l_whence = SEEK_SET;
    fl.l_start = 0;
    fl.l_len = 0;            // 锁定整个文件

    int res = fcntl(fd, F_SETLK, &fl);
    close(fd);

    if (res == -1) {
        qDebug() << "文件被其他进程锁定，无法独占打开：" << filePath;
        return false;
    }

    return true;

#else
    qDebug() << "当前平台不支持文件独占检测";
    return true; // 其他平台暂时跳过检测
#endif
}

void DisposeThread::run()
{

    int totalFiles = 0;
    int matchedByName = 0;
    int matchedByContent = 0;
    int movedCount = 0;
    int skippedCount = 0;

    signal_workStatus(true);
    signal_workMsg("扫描启动!");

    ScanRuleService scanRuleService;
    isRun = true;
    bool isError = false;

    // 读取配置参数
    QString scanDir = QGlobalConfig::getInstance().read("param", "scanDir", "").toString();        // 要扫描的目录
    QString scanMoveDir = QGlobalConfig::getInstance().read("param", "scanMoveDir", "").toString(); // 未匹配文件的目标目录
    if (scanDir.isEmpty()) {
        isError = true;
        isRun = false;
        signal_workMsg("扫描目录为空，请检查配置！");
    }else{
        // 获取扫描规则
        QList<ScanRule> ruleList;
        if (!scanRuleService.getList(ruleList)) {
            isError = true;
            isRun = false;
            signal_workMsg("获取扫描策略列表失败!");
        }else{
            // 整理规则
            QStringList nameRules; // 文件名匹配规则
            QStringList contentRules; // 文件内容匹配规则
            QMap<QString, QString> byNameDirMap; // 文件名匹配 -> 移动目录
            QMap<QString, QString> byContentDirMap; // 文件内容匹配 -> 移动目录

            for (const ScanRule& item : qAsConst(ruleList)) {
                if (item.getByFileName()) {
                    nameRules.append(item.getFilterContent());
                    byNameDirMap[item.getFilterContent()] = item.getMoveDir();
                }
                if (item.getByFileContent()) {
                    contentRules.append(item.getFilterContent());
                    byContentDirMap[item.getFilterContent()] = item.getMoveDir();
                }
            }

            while(isRun){
                // 扫描当前目录下的所有文件（不进入子目录）
                QDir dir(scanDir);
                QFileInfoList fileList = dir.entryInfoList(QDir::Files); // 只获取当前目录下的文件

                for (const QFileInfo &fileInfo : qAsConst(fileList)) {
                    if (!isRun) break;

                    QString filePath = fileInfo.absoluteFilePath();
                    QString fileName = fileInfo.fileName();

                    bool contained = false;

                    bool matched = false;

                    // 检查是否满足文件名匹配条件
                    for (const QString& pattern : qAsConst(nameRules)) {
                        if (fileName.contains(pattern, Qt::CaseInsensitive)) {
                            contained = true;
                            QString targetDir = byNameDirMap[pattern];
                            matched = moveFile(filePath, targetDir);
                            if (matched) {
                                matchedByName++;
                                movedCount++;
                            } else {
                                skippedCount++;
                            }
                            break;
                        }
                    }

                    // 如果没有文件名匹配，尝试内容匹配
                    if (!matched && !contentRules.isEmpty()) {

                        // 检查是否可以独占打开文件
                        if (!isFileOpenable(filePath)) {
                            skippedCount++;
                            continue;
                        }

                        // 独占打开成功，再使用 QFile 读取内容
                        QFile file(filePath);
                        if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
                            QTextStream in(&file);
                            QString content = in.readAll();
                            file.close();

                            for (const QString& keyword : qAsConst(contentRules)) {
                                if (content.contains(keyword, Qt::CaseInsensitive)) {
                                    contained = true;
                                    QString targetDir = byContentDirMap[keyword];
                                    matched = moveFile(filePath, targetDir);
                                    if (matched) {
                                        matchedByContent++;
                                        movedCount++;
                                    } else {
                                        skippedCount++;
                                    }
                                    break;
                                }
                            }
                        } else {
                            skippedCount++;
                            qDebug() << "无法打开文件进行内容扫描：" << filePath;
                        }
                    }

                    totalFiles++;

                    if(!contained){
                        moveFile(filePath, scanMoveDir);
                    }
                    QThread::msleep(1);// 避免 CPU 占用过高
                }
                QThread::msleep(1);// 避免 CPU 占用过高
            }
        }
    }


    signal_workStatus(false);
    if (!isError) {
        QString msg = QString("扫描停止！共处理 %1 个文件，成功移动 %2 个（文件名匹配：%3，内容匹配：%4）")
                .arg(totalFiles).arg(movedCount)
                .arg(matchedByName).arg(matchedByContent);
        signal_workMsg(msg);
    } else {
        signal_workMsg("扫描异常终止！");
    }
}
